import type {
  UploaderConfigType,
  FileObjType,
  ViewContainerType,
  UploadHooks,
} from '../types/index.ts'

import { FormatFileSize } from '../utils/index.ts'

import { ref, reactive, createVNode, render, h, toRefs } from 'vue'
// 各种服务
import {
  FileService,
  HashService,
  QueueService,
  RequestService,
  LogService,
  StoreService
} from '../service/index.ts'
import type { Queue } from '../service/index.ts'

import { Message } from '../hooks/Message.ts'
// 事件监听系统
import LifeCycle from '../hooks/lifeCycle.ts'
// 默认视图容器
import ViewContainer from '../view/ViewContainer.vue'

enum ItemStatus {
  waiting = '等待上传',
  checkMD5 = '校验MD5',
  uploading = '分片上传中',
  merge = '合并中',
  abort = '已取消',
  retry = '重试中',
  paused = '暂停中',
  success = '上传成功',
  error = '上传失败',
}

// 上传主引擎类
class UploadController {
  // UI部件挂载的节点元素
  private el: HTMLElement

  // 并发队列实例
  private Queue: Queue | null

  // 上传配置
  private options = {
    // 分片大小
    chunkSize: 1024 * 1024 * 10,
    // 可选择的文件类型，多个类型用英文逗号隔开
    accept: '*',
    // 分片队列最大并发数
    queueMax: 3,
    // 分片最大重试次数
    retryMax: 3,
    // 一次上传的最大文件大小,默认5GB
    maxTotalSize: 1024 * 1024 * 500 * 5,
    // 是否允许选择文件夹
    folder: false,
  }

  // 自定义事件
  public Hooks
  // 日志服务
  public LogService: LogService
  // 状态服务
  public StoreService: StoreService

  constructor({ el, options, customViewContainer, hooks }: UploaderConfigType) {
    // 指定渲染元素
    this.el = el
    // 状态服务
    this.StoreService = new StoreService()

    // 配置项
    options.chunkSize && (this.options.chunkSize = options.chunkSize)
    options.accept && (this.options.accept = options.accept)
    options.queueMax && (this.options.queueMax = options.queueMax)
    options.retryMax && (this.options.retryMax = options.retryMax)
    options.maxTotalSize && (this.options.maxTotalSize = options.maxTotalSize)
    options.folder && (this.options.folder = options.folder)

    // 日志服务
    this.LogService = new LogService()
    // 创建事件系统
    this.Hooks = new LifeCycle(hooks, this.LogService)
    // 创建上传队列，最大并发 6，最多重试 3 次
    this.Queue = new QueueService(
      this.options.queueMax,
      this.options.chunkSize,
      this.Hooks,
      this.LogService,
      this.StoreService,
      RequestService,
    )
    // 渲染UI组件
    this.renderUIComponents(customViewContainer)
  }

  // 渲染UI
  renderUIComponents(customViewContainer: any | undefined) {
    const props: ViewContainerType = reactive({
      ref: (instance: any) => {
        console.log('视图容器实例', instance)
        // 当组件挂载时，instance是组件实例
        // childInstance.value = instance
      },
      maxTotalSize: this.options.maxTotalSize,
      fileList: this.StoreService.fileList,
      accept: this.options.accept,
      folder: this.options.folder,
      filesTotalSize: this.StoreService.filesTotalSize,
      chunkSize: this.options.chunkSize,
      queueStatus: this.StoreService.queueStatus,
      addFile: (files: FileList) =>
        FileService.addFile(files, this.options, this.Hooks, this.LogService, this.StoreService),
      allStart: () => this.startUpload('all'),
      allPause: () => this.Queue?.pauseAll(), // 暂停所有上传任务
      allResume: () => this.Queue?.resumeAll(), // 恢复所有上传任务
      allDel: () => FileService.delAllFile(this.Queue, this.StoreService), // 重置所有上传任务
      // 全局上传状态
      globalUploadStatus: this.StoreService.globalUploadStatus,
      // 开始上传
      itemStart: (item: FileObjType) => this.startUpload('item', item),
      // 删除指定文件
      itemDel: (item: FileObjType) => FileService.delFile(item, this.Queue, this.StoreService),
      // 暂停指定任务组上传
      itemPause: (item: FileObjType) => this.Queue?.pauseGroup(item.fileHash),
      // 恢复指定任务组上传
      itemResume: (item: FileObjType) => this.Queue?.resumeGroup(item.fileHash),
      // 格式化文件大小
      formatFileSize: (size: number) => FormatFileSize(size),
      // 格式化上传速度
      // formatUploadSpeed: (speed: number) => this.formatUploadSpeed(speed),
      // 队列状态信息
      statusEnum: ItemStatus,
      logs: this.LogService.logs,
      // 清空日志
      clearLogs: () => this.LogService.clear(),
    })
    // 视图容器部件 虚拟节点
    const ViewContainerVnode = h(customViewContainer || ViewContainer, { options: props })
    // 合并虚拟节点
    const vnodeContainer = h('div', [ViewContainerVnode])
    // 渲染到容器
    render(vnodeContainer, this.el)

    this.LogService.addLog('上传引擎：引擎和UI已初始化渲染完成', 'info')
  }

  // 开始上传
  async startUpload(uploadType: 'all' | 'item', item?: FileObjType) {
    try {
      if (!this.StoreService.fileList.value.length) {
        return Message('warning', '没有文件可上传')
      }
      this.LogService.addLog(`开始上传文件...`, 'success')
      // 更新上传状态为 => 上传中
      this.StoreService.globalUploadStatus.value = 'uploading'

      // 上传所有文件
      if (uploadType === 'all') {
        // 1、统一生成分片对象
        await FileService.GenerateChunk(
          this.StoreService.fileList.value,
          this.options.chunkSize,
          this.Hooks,
          this.LogService,
        )

        // 2、统一计算哈希
        await HashService.HashWorker(this.StoreService.fileList.value, this.Hooks, this.LogService)

        // 3. 统一检查已上传分片
        // const result = await RequestService.checkUploadedChunks(this.Hooks,this.LogService)
        // if (result === false) return

        // 4. 添加分片上传任务到队列
        await RequestService.addQueue(this.Queue, this.Hooks, this.LogService, this.StoreService)

        // 5.合并分片任务放在队列里了
      }
      // 上传单个选中文件
      else {
        if (!item) return
        // 1、统一生成分片对象
        await FileService.GenerateChunk([item], this.options.chunkSize, this.Hooks, this.LogService)

        // 2、统一计算哈希
        await HashService.HashWorker([item], this.Hooks, this.LogService)

        // 3. 统一检查已上传分片
        // const result = await RequestService.checkUploadedChunks(this.Hooks,this.LogService)
        // if (result === false) return

        // 4. 添加分片上传任务到队列
        await RequestService.addQueue(this.Queue, this.Hooks, this.LogService, this.StoreService)

      }
    } catch (error) {
      console.log('🚀 意外错误', error)
      if (error && typeof error === 'object' && 'isCanceled' in error && !error.isCanceled) {
        // 更新上传状态为 =》 失败
        this.StoreService.globalUploadStatus.value = 'start'
      }
    }
  }

  /**
   * 注册单个钩子
   */
  on<K extends keyof UploadHooks>(name: K, handler: UploadHooks[K]) {
    this.Hooks.registerHook(name, handler)
    return this // 支持链式调用
  }
}

export { UploadController }
